/*
 * @Author      : ZhouQiJun
 * @Date        : 2025-08-06 23:59:51
 * @LastEditors : ZhouQiJun
 * @LastEditTime: 2025-08-07 02:09:50
 * @Description :
 * // 地理坐标转换库
 * // https://www.npmjs.com/package/gcoord
 */
import type { ProjCode } from '@ol/types'
import gcoord, { type CRSTypes, type Position } from 'gcoord'

type Projections = {
  [key in ProjCode]: CRSTypes
}

const projections: Projections = {
  'EPSG:4326': gcoord.EPSG4326,
  'EPSG:3857': gcoord.EPSG3857,
}

/**
 * 坐标投影转换静态类。
 */
export default class Transforms {
  /**
   * 预设投影，方便其他地方引用。
   */
  public static PROJ = {
    WGS84: 'EPSG:4326',
    MERCATOR: 'EPSG:3857',
    CHINA2000: 'EPSG:4490',
  }

  /**
   * 转换边界，
   * @param coordinates
   * @param from
   * @param to
   */
  public static extent(coordinates: number[], from: ProjCode, to: ProjCode): number[] {
    if (from === to) return coordinates

    const min = Transforms.point([coordinates[0], coordinates[1]], from, to)
    const max = Transforms.point([coordinates[2], coordinates[3]], from, to)

    return [min[0], min[1], max[0], max[1]]
  }

  /**
   * 转换一系列坐标对 (coordinates 格式为：[x1,y1,x2,y2,x3,y3,...])
   * 坐标对必须是成对的，即偶数个数字。
   * @param coordinates
   * @param from
   * @param to
   */
  public static series(coordinates: number[], from: ProjCode, to: ProjCode): number[] {
    const buffer: number[] = []
    const size = coordinates.length
    if (size % 2 !== 0) {
      console.warn('Coordinates length is not even, can not convert coordinate pairs.')
      return buffer
    }
    for (let i = 0; i < size; i += 2) {
      const point = [coordinates[i], coordinates[i + 1]]
      buffer.push(...Transforms.point(point, from, to))
    }
    return buffer
  }

  public static point(coordinates: number[], from: ProjCode, to: ProjCode): number[] {
    if (from === to) return coordinates

    return gcoord.transform(coordinates as Position, projections[from], projections[to])
  }

  public static polyline(coordinates: number[][], from: ProjCode, to: ProjCode): number[][] {
    return coordinates.map((point) => Transforms.point(point, from, to))
  }

  public static multiPolyline(coordinates: number[][][], from: ProjCode, to: ProjCode): number[][][] {
    return coordinates.map((line) => Transforms.polyline(line, from, to))
  }

  public static polygon(coordinates: number[][][], from: ProjCode, to: ProjCode): number[][][] {
    return coordinates.map((line) => Transforms.polyline(line, from, to))
  }

  public static multiPolygon(coordinates: number[][][][], from: ProjCode, to: ProjCode): number[][][][] {
    return coordinates.map((polygon) => Transforms.polygon(polygon, from, to))
  }

  /**
   * WebMercator坐标转经纬度坐标。
   * @param x WebMercator x
   * @param y WebMercator y
   * @return 经纬度坐标
   */
  public static mercator2degrees(x: number, y: number): Position {
    const lng = (x / 20037508.34) * 180
    const _lat = (y / 20037508.34) * 180
    const lat = (180 / Math.PI) * (2 * Math.atan(Math.exp((_lat * Math.PI) / 180)) - Math.PI / 2)
    return [lng, lat]
  }
}
